#ifndef CUSTOMMETER_HPP
#define CUSTOMMETER_HPP
#include "adc.hpp"
#include "arm_math.h"
#define CUSTOMMETER_CHANNEL_MAX_SURPPORT    8

using namespace device;

namespace measure
{
class calculate   ///>计量校准 类
{    
	public:    
    #define CURRENT_NUM                 5

    static short CurrentBuf[CURRENT_NUM];

    static void RefreshCalculatePara(short IfrmSet, short InSet, short IiSetting, short IinSetting); ///>刷新校准参数


    static short CalculateAdcPeakVal(short ChNum, short Val);
    static short CalculateCurrentVal(short ChNum);
    static short FindPeakVal(unsigned short* pData, short DataPos, short AdcChNum);
    static bool PrepareSampleData(unsigned short const* pSrc);
    
    static char TransCurrentVal(void);
    static void CalGndCurrent(void);
    static void DbgCalVal(short ChNum);
    static bool InstantJdg(short channel);
protected:
    static bool StartFilterFlag;
private:
    #define CUR_FILTR_NUM               4
    #define ADC_CYCLE_NUM               16
    #define ADC_CYCLE_TIM               4
    #define SMP_LOOP_NUM                (ADC_CYCLE_NUM*ADC_CYCLE_TIM)
    #define ADC_DMA_BLK_SIZE            (ADC_CYCLE_NUM*CUSTOMMETER_CHANNEL_MAX_SURPPORT)
    #define ADC_CYC_DATA_NUM            (SMP_LOOP_NUM*CUSTOMMETER_CHANNEL_MAX_SURPPORT)
    #define APP_ADC_NO_CHANNEL          0xFF
    #define ADC_CH_SHIFT                3  //(2^3)=CUSTOMMETER_CHANNEL_MAX_SURPPORT
    #define SMP_ADC_MID_LVL             2048  ///偏移值
    enum IndType{
        FE_MAG_IND = 0,
        ROG_MAG_IND = 2
    };
    
    enum SampleType{
        SMP_DC,     //整流
        SMP_SHIFT,  //直流偏置
        SMP_CMP     //电流方向
    };
    enum CalPhEnum{
        CAL_NO_PH   = 0x00,
        CAL_PH_A    = 0x01,
        CAL_PH_B    = 0x02,
        CAL_PH_C    = 0x04,
        CAL_PH_N    = 0x08,
        CAL_PH_G    = 0x10,
        CAL_PH_ABC  = 0x07,
        CAL_PH_BCN  = 0x0E,
        CAL_PH_ABCN = 0x0F,
    };
    

    struct LinearTable{
        struct{
            struct{
                short RealData;
                short AdcData;
            }DataTable[30];
            short DataNum;
            enum SampleType SmpType;
            enum CalPhEnum ApplyPh;
            short Range[2];

            
        }DataItem[4];
    };
    struct LinearIndex{
        short IfrmType;
        short InType;
        short IndexNum;
    };
    enum ChannelType{
        CH0,            ///<Low Lvl Adc ch
        CH1,            ///<Hign Lvl Adc Ch
        NO_CH = 0xFF    ///<No channel set
    };
    
    enum InterpItem{
        INTERP_CH0_RMS,
        INTERP_CH0_PEAK,
        INTERP_CH1_RMS,
        INTERP_CH1_PEAK
    };

    struct ChPhase{
        enum CalPhEnum          Phase;
        short                   Ch0AdcSeqNum;
        short                   Ch1AdcSeqNum;
        short                   ChNegtiveFlag;
    };
    struct ChAdc{
        short                   AdcChNum;
        enum ChannelType        Ch;
        enum CalPhEnum          Phase;
    };
    static short AdcDataPos;
    static short AdcPeakBuf[CUSTOMMETER_CHANNEL_MAX_SURPPORT];
    static short SmpPeak[CUSTOMMETER_CHANNEL_MAX_SURPPORT];
    static short SmpRms[CUSTOMMETER_CHANNEL_MAX_SURPPORT];
    static short CurrentVal[CUSTOMMETER_CHANNEL_MAX_SURPPORT];
    static short CurrPhPosBuf[CUSTOMMETER_CHANNEL_MAX_SURPPORT];
    static short CurrPhPos[CUSTOMMETER_CHANNEL_MAX_SURPPORT];
    
    static const struct ChPhase ChannelPhaseIndex[];
    static const struct ChAdc ChAdcIndex[];
    static const struct LinearTable LinearTableArray[];
    static const struct LinearIndex LinearIndexArray[];
    static short Ifrm;     ///<Frame current 
    static short In;       ///<Rated current
    static short FilterArrayBuf[ADC_CYCLE_NUM+CUR_FILTR_NUM];
    static short SampleArrayBuf[ADC_CYC_DATA_NUM];
    static arm_matrix_instance_q15 MatSrc;
    static arm_matrix_instance_q15 MatDst;
    static const struct LinearTable* pLinearTable;
    static short AdcMidLvlBuf[CUSTOMMETER_CHANNEL_MAX_SURPPORT];
    static short Ii;
    static short Iin;
    
    static short IilLvl;
    static short IinlLvl;
    static short IihLvl;
    static short IinhLvl;
    static char Ch0Flag;
    static char Ch1Flag;
    
    static short GetLinearIndex(void);

    static short CalCurrentLinearInterp(short Num, short InputVal);       ///<Input-AdcVal;       RtnVal-Current calculate value;
    static short CalAdcLinearInterp(short Num, short InputVal);           ///<Input-Current val;  RtnVal-Adc calculate value;
    
    static __INLINE short CalRmsDC(short* pData, short AdcChNum);
    static __INLINE short CalRmsShift(short* pData, short AdcChNum);
    
    
    static char GetFilterArray(unsigned short const* pData, short DataPos); ///> 获取滤波数据
    static void Filter(char AdcChNum); ////>滤波
    
};


class custommeter:public calculate
{
    private:
        static bool mLock;
        static bool mFirstComplated;
        static uint32_t mIndex;
        static adc *mAdc;
        static void ConvertedCallBack(uint16_t *usResult, uint16_t usLen);
        static void CustomMeterThread(void *args);
        
    public:
        typedef struct
        {
            bool bLimitUpperEnable;										///<下限值使能
            bool bLimitEvent;													///<事件标记
            adc::AdcChannelTPDF tChannel;							///<通道
            uint32_t uiLimitCountUpper;								///<上限值计数
            int32_t iRecordUpper;											///<记录最大值
            uint32_t uiRealValue;											///<有效值
        }MeterChannelTPDF;													///<计量通道定义
        
        /** 
        * @brief      	数据超限委托方法
        * @param[in]  	ucChannel   	通道
        * @param[in]  	ucFlag   			标记(0:超上限,1:超下限)
        * @param[in]  	iValue   			记录值
        * @retval     	None
        */
        typedef void (*ValueOutOfLimitDelegate)(uint8_t ucChannel, uint8_t ucFlag, int32_t iValue);
        typedef void (*ValueConvertedDelegate)(void);
        
        static uint32_t ChannelCount;								///<通道数量
        static uint32_t Frequnce;										///<采样频率
        static uint32_t SampleLen;									///<单次采样周期
        static uint32_t EfectiveSampleLen;					///<有效值采样周期
        static uint16_t* SampleBuff;								///<缓存,建议长度>ChannelCount * SampleLen
        static uint16_t* EfectiveSampleBuff;				///<缓存,建议长度>ChannelCount * EfectiveSampleLen
        static MeterChannelTPDF MeterChannel[CUSTOMMETER_CHANNEL_MAX_SURPPORT];		///<通道
        static ValueOutOfLimitDelegate ValueOutOfLimitCallback;
        static ValueConvertedDelegate ValueConvertedCallback;
        static void InstantProtect(void);
        
        static bool Start(adc::AdcInstanceTPDF tAdcInstance, uint32_t uiStackDeep, uint8_t ucThreadPrio);
};
}
#endif
